/**
 *  Copyright 23.07.2012 oliver.keusemann@googlemail.com
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package de.xelerity.geolessi.types.mixed;

import java.io.Serializable;
import de.xelerity.helper.StringFunktionen;

public class Koordinate implements Serializable {

	private static final long serialVersionUID = -5297141507821830791L;

	double longitude; // X
	double latitude; // Y
	private static double RA = Math.PI / 180.0;

	public Koordinate(double lat, double lng) {
		latitude = lat;
		longitude = lng;
	}

	public Koordinate(Number lat, Number lng) {
		if (lat == null || lng == null) {
			return;
		}
		latitude = lat.doubleValue();
		longitude = lng.doubleValue();
	}

	public Koordinate(Koordinate K) {
		if (K != null) {
			latitude = K.getLatitude();
			longitude = K.getLongitude();
		}
	}

	public Koordinate(String lat, String lng) {
		if (lat == null) {
			return;
		}
		if (lng == null) {
			return;
		}

		lat = lat.replaceAll(" ", "");
		lng = lng.replaceAll(" ", "");
		lat = lat.replace(',', '.');
		lng = lng.replace(',', '.');

		latitude = Double.parseDouble(lat);
		longitude = Double.parseDouble(lng);
	}

	public Koordinate() {
		latitude = 0;
		longitude = 0;
	}

	public boolean isValid() {
		return (latitude > 0 && longitude > 0 && latitude < 90 && longitude < 90);
	}

	public long distance(double lat, double lng) {
		double b = lat * RA, c = latitude * RA, d = b - c;
		double g = lng * RA - longitude * RA;
		double f = 2 * Math
				.asin(Math.sqrt(Math.pow(Math.sin(d / 2), 2) + Math.cos(b) * Math.cos(c) * Math.pow(Math.sin(g / 2), 2)));
		return Math.round(f * 6378137);
	}

	public static double MeterinUSG84_X(Koordinate pReferenz, double fmeter) {
		fmeter = fmeter / 6378137;

		double b = pReferenz.getLatitude() * RA, c = pReferenz.getLatitude() * RA;

		double X = Math.cos(b) * Math.cos(c);

		double g = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(fmeter / 2), 2) / X));

		return ((g + pReferenz.getLongitude() * RA) / RA) - pReferenz.getLongitude();

	}

	public static double MeterinUSG84_Y(Koordinate pReferenz, double fmeter) {
		fmeter = fmeter / 6378137;
		return ((fmeter - pReferenz.getLatitude() * RA) / RA) + pReferenz.getLatitude();
	}

	public long distance(Number lat, Number lng) {
		if (lat == null || lng == null) {
			return 0;
		}
		return distance(lat.doubleValue(), lng.doubleValue());
	}

	public long distance(Koordinate P) {
		if (P == null) {
			return 0;
		}

		return distance(P.getLatitude(), P.getLongitude());
	}

	public double getLatitude() {
		return latitude;
	}

	public void setLatitude(double latitude) {
		this.latitude = latitude;
	}

	public double getLongitude() {
		return longitude;
	}

	public void setLongitude(double longitude) {
		this.longitude = longitude;
	}

	public String toString() {
		return "(" + latitude + "," + longitude + ")";
	}

	public boolean equals(Koordinate A) {
		return A != null
				&& (toBahnCoord(A.getLatitude()).equals(toBahnCoord(getLatitude())) && toBahnCoord(A.getLongitude()).equals(
						toBahnCoord(getLongitude())));
	}

	public static Koordinate mittel(Koordinate A, Koordinate B) {
		if ((A != null && A.isValid()) && (B == null || !B.isValid())) {
			return A;
		}

		if ((B != null && B.isValid()) && (A == null || !A.isValid())) {
			return B;
		}

		if ((B == null || !B.isValid()) && (A == null || !A.isValid())) {
			return new Koordinate();
		}

		double X1 = Math.cos(A.getLatitude() * RA) * Math.cos(A.getLongitude() * RA);
		double Y1 = Math.cos(A.getLatitude() * RA) * Math.sin(A.getLongitude() * RA);
		double Z1 = Math.sin(A.getLatitude() * RA);

		double X2 = Math.cos(B.getLatitude() * RA) * Math.cos(B.getLongitude() * RA);
		double Y2 = Math.cos(B.getLatitude() * RA) * Math.sin(B.getLongitude() * RA);
		double Z2 = Math.sin(B.getLatitude() * RA);

		double X = (X1 + X2) / 2;
		double Y = (Y1 + Y2) / 2;
		double Z = (Z1 + Z2) / 2;

		double Lon = Math.atan2(Y, X);
		double Hyp = Math.sqrt(X * X + Y * Y);
		double Lat = Math.atan2(Z, Hyp);

		return new Koordinate(Lat / RA, Lon / RA);
	}

	// Bahnkoordinaten 6 Nachkommastellen
	public static Koordinate fromBahnCoord(String X, String Y) {
		if (StringFunktionen.isEmptyTrimed(X) || StringFunktionen.isEmptyTrimed(Y)) {
			return new Koordinate();
		}
		try {
			String AA = (X).substring(X.length() - 6);
			String BB = (X).substring(0, X.length() - 6);
			String CC = (Y).substring(Y.length() - 6);
			String DD = (Y).substring(0, Y.length() - 6);
			return new Koordinate(DD + "." + CC, BB + "." + AA);
		} catch (Throwable e) {
			return new Koordinate();
		}
	}

	public void raster(int pRaster) {
		latitude = _raster(latitude, pRaster);
		longitude = _raster(longitude, pRaster);
	}

	private static double _raster(double pX, int pRaster) {
		String A = R(pX) + "";

		String vk = ((int) R(pX)) + "";
		int _vk = Integer.parseInt(vk, 10);
		int ix = A.indexOf(".");
		if (ix < 0) {
			ix = A.indexOf(",");
		}
		String nk3 = (A + "00000").substring(ix + 1, ix + 4);
		int _nk3 = Integer.parseInt(nk3);
		String nk6 = (A + "0000000000").substring(ix + 4, ix + 7);
		int _nk6 = Integer.parseInt(nk6, 10);

		double rasterschritte = 1.0 / ((double) pRaster);

		for (int i = 1; i <= pRaster; i++) {
			double x = rasterschritte * i;
			// System.out.println(x);
			if ((_nk6 / 1000.0) < x) {
				if ((_nk6 / 1000.0) < (x / 2.0)) {
					_nk6 = (int) (((i - 1) * rasterschritte) * 1000.0);
				} else {
					_nk6 = (int) (x * 1000.0);
					if (i == pRaster) {
						_nk6 = 0;
						_nk3 = _nk3 + 1;
						if (_nk3 >= 1000) {
							_nk3 = 0;
							_vk++;
						}
					}
				}
				break;
			}
		}

		return Double.parseDouble(_vk + "." + StringFunktionen.minLenRight(_nk3 + "", 3, '0')
				+ StringFunktionen.minLenRight(_nk6 + "", 3, '0'));
	}

	private static double R(double D) {
		return Math.round(D * 1000000.0) / 1000000.0;
	}

	public static String toBahnCoord(double Z) {
		String X = ("" + Z).replace(',', '.');
		int i = X.indexOf(".");
		String a = X.substring(0, i);
		String b = (X.substring(i + 1) + "0000000000").substring(0, 6);
		return a + b;
	}

	public static Koordinate RUIT = new Koordinate(48.731016, 9.253851);
	public static Koordinate STADTMITTE = new Koordinate(48.776004, 9.172359);
	public static Koordinate FEUERSEE = new Koordinate(48.772963, 9.166371);
	public static Koordinate CHARLOTTENPLATZ = new Koordinate(48.776075, 9.183108);
	public static Koordinate REINSBURGSTRASSE = new Koordinate(48.770163, 9.165748);
	public static Koordinate ZINSHOLZ = new Koordinate(48.726, 9.261722);

	public static void main(String[] args) {

		Koordinate A1 = new Koordinate(47.731016, 9.253851);

		Koordinate A2 = new Koordinate(47.731016, 8.253851);

		System.out.println(A1.distance(A2));

		if (1 == 1)
			return;

		A2.raster(4);

		System.out.println(A2);

		// System.out.println(A1.distance(A2));

		if (11 == 11) {
			System.exit(0);
		}

		String D = "7123456";

		String AA = (D).substring(D.length() - 6);
		System.out.println(AA);

		String BB = (D).substring(0, D.length() - 6);
		System.out.println(BB);

		Koordinate A = new Koordinate(48.530177, 2.249923);
		Koordinate B = new Koordinate(48.720577, 9.291923);

		// System.out.println(A.distance(B));

		A = new Koordinate("48,720577", "2,255522");
		B = new Koordinate("48,720577", "2.355522");

		// System.out.println(A);

	}

}
